The following example creates a closure around a local function called elapsedTime
. This closure can then be used to keep track of the time that has passed since the last time it was called. In a ScriptX title, it could be used to do simple timekeeping without creating a clock, and without defining any new global variables. ScriptX defines a global instance of CalendarClock
for simple timekeeping, stored in a global variable called theCalendarClock
. (Since it is accurate only to one second, the clock stored in theCalendarClock
is not intended for system timekeeping.) The closure function that is defined here refers to this clock internally.
function closureMaker -> (
-- x is the free variable or closure variable
local x := theCalendarClock.time
-- elapsedTime is the function that will be returned as a closure
local fn elapsedTime -> (
local result := theCalendarClock.time - x
x := theCalendarClock.time
result
)
-- the next expression is the return value of this function
-- it returns the local function elapsedTime
-- that turns it into a closure
elapsedTime
)
#<ByteCodeMethod Scratch:closureMaker of 0 arguments>
In this example, a closure is created when the local function is returned by a global function. This means that elapsedTime
"escapes" to the top level, even though it was defined as a local function.
Each time closureMaker
is called, it returns another closure. The closures it creates share code with the other closures on the elapsedTime
function, but each closure maintains its own value for the closure variable x
. The value of this closure variable is accessible only through the closure. In the following example, a call to timeKeeper
answers the question, "How much time has passed since I called you last?"
timeKeeper := closureMaker() -- create a closure
#<ByteCodeMethod anonymous of 0 arguments>
-- now, wait seven seconds and try timeKeeper
timeKeeper()
0:0:7:0 as Time
The ScriptX closure construct is more versatile and powerful than a static variable in C or C++. A closure can be used to encapsulate a value, such as a counter, so that it is only accessible through a function. The following example creates a closure from an anonymous function.
-- defines a closure on an anonymous function
function counter -> (local x:0; (-> x := x + 1))
Each time counter
is called, it returns a new closure that behaves isomorphically with repect to other counters, while retaining its own closure variables, as the following example demonstrates:
myCounter := counter()
myCounter()
1
myCounter()
2
-- now create another counter
global anotherCounter := counter()
anotherCounter()
1
myCounter() -- myCounter still retains its own closure variables
3
anotherCounter() -- so does anotherCounter
2
This document is part of the ScriptX Language Guide, one of the volumes of the ScriptX Technical Reference Series. ScriptX is developed by the ScriptX Engineering Team at Apple Computer, successor to the Kaleida Engineering Team at Kaleida Labs, Inc.